home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Eagles Nest BBS 8
/
Eagles_Nest_Mac_Collection_Disc_8.TOAST
/
Developer Tools⁄Additions
/
TextPertDK#1
/
MPW C Sources & Examples.image
/
Example1
/
Example1.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-03-05
|
38KB
|
1,488 lines
/*•———————————————————————————————————————————————————————————————————————————————————•
|
| Example 1:
|
| © 1992, CTA, Inc.. All rights reserved.
|
| This example program demonstrates the fundamental calls used in
| incorporating TextPert OCR in your application. This example does
| not take advantage of all calls to the TextPert engine, but it does
| access an important subset of the entire set of calls.
|
| The TextPert calls used in this example are:
|
| IMGetInfo
| IMGetMaxStrip
| IMFree
| IMLockZone
| IMNewScale
| IMTiff2hIM
| IMUnlockZone
| LTSet to change the resolution
| LTFree
| PAObtainObjects
| TPDispose
| TPAlloc
| TPRead
|
•———————————————————————————————————————————————————————————————————————————————————•*/
#include "Example1.h"
/*•————————————————————————————————————————————————•
| Prototypes.
•————————————————————————————————————————————————•*/
static void ToolBoxInit();
static void MenuBarInit();
static void HandleEvent();
static void DoCommand( long menuChoice );
static void HandleAppleChoice( int theItem );
static void HandleFileChoice( int theItem );
static void DispatchOurWindowClicks();
static void InitTheTextPertEngine();
static void OpenAnImage();
static void AnalyzeTheImage();
static void ReadTheImage();
static void DisposeTheImageAndTheLayout();
static void FreeTheEngine();
static short ShowImageChoiceDialog();
static void InputImageFromDisk();
static void InputImageFromScanner();
static void PurgehIM(IMHandle *thehIM);
static void ShowMainWindow();
static Boolean ShowStartDialog();
static void AboutDialog();
static void InformAlert( Str255 myString );
static void ErrorAlert( Str255 myString );
static void EngineError();
static void HearSnd();
/*•————————————————————————————————————————————————•
| These variables are typical for what you will
| need when working with the TextPert engine.
•————————————————————————————————————————————————•*/
TPHandle hTP = 0L;
IMHandle hIM = 0L;
LOHandle hLO = 0L;
TPTextOut *TextOutBufferPtr = 0L;
/*•————————————————————————————————————————————————•
| These are global variables that are used by
| this example. Some are initialized with
| default values
•————————————————————————————————————————————————•*/
Boolean gDone = false,gShowStart = true;
short gStartUpVolume = 0,
gBrightness = 6,
gContrast = 4,
gResolution = 300;
MenuHandle gMyMenus[2];
EventRecord gTheEvent;
WindowPtr gMyWindowPtr;
Cursor gWatchCursor;
Rect gRect[6] = {{50,176,89,479},
{97,176,136,479},
{144,176,183,479},
{191,176,230,479},
{239,176,278,479},
{286,176,325,479}};
/*•———————————————————————————————————————————————————————————————————————————————————•
| This is the main routine for the program.
•———————————————————————————————————————————————————————————————————————————————————•*/
main()
{
ToolBoxInit();
MenuBarInit();
gMyWindowPtr = GetNewDialog(402, 0L , ((WindowPtr) -1L));
if (!gMyWindowPtr)
ErrorAlert("\pCouldn't load the main window.");
while (!gDone) {
if (gShowStart) {
gShowStart = false;
gDone = ShowStartDialog();
if (!gDone)
ShowMainWindow();
}
HandleEvent();
}
DisposeDialog((DialogPtr)gMyWindowPtr);
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| Initialize the ToolBox Managers.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void ToolBoxInit()
{
CursHandle hCurs;
MaxApplZone();
InitGraf( &qd.thePort );
InitFonts();
FlushEvents( everyEvent, 0 );
InitWindows();
InitMenus();
TEInit();
InitDialogs( 0L );
InitCursor();
hCurs = GetCursor(watchCursor);
gWatchCursor = **hCurs;
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| Set up the menubar.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void MenuBarInit()
{
Handle myMenuBar;
myMenuBar = GetNewMBar( 400 );
SetMenuBar( myMenuBar );
gMyMenus[0] = GetMHandle( 400 );
AddResMenu( gMyMenus[0] , 'DRVR' );
gMyMenus[1] = GetMHandle( 401 );
DrawMenuBar();
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| Dispatch the Events.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void HandleEvent()
{
WindowPtr whichWindow;
register char theChar;
GrafPtr savePort;
WaitNextEvent( everyEvent, &gTheEvent, 1000 , 0L );
switch( gTheEvent.what )
{
case mouseDown:
switch( FindWindow( gTheEvent.where, &whichWindow) )
{
case inDesk:
case inGoAway:
break;
case inMenuBar:
DoCommand( MenuSelect(gTheEvent.where) );
break;
case inSysWindow:
SystemClick( &gTheEvent, whichWindow);
break;
case inDrag:
case inGrow:
break;
case inContent:
if (whichWindow != FrontWindow())
SelectWindow(whichWindow);
else {
if ((gMyWindowPtr != NULL) &&
(gMyWindowPtr == FrontWindow()))
DispatchOurWindowClicks();
}
break;
default: ;
}
break;
case keyDown:
case autoKey:
theChar = gTheEvent.message & charCodeMask;
if ((gTheEvent.modifiers & cmdKey) != 0)
DoCommand(MenuKey( theChar));
break;
case activateEvt:
InvalRect(&gMyWindowPtr->portRect);
break;
case updateEvt:
if ((gMyWindowPtr != NULL) && (((WindowPtr)gTheEvent.message) == gMyWindowPtr)) {
GetPort(&savePort);
SetPort(gMyWindowPtr);
BeginUpdate(gMyWindowPtr);
DrawDialog(gMyWindowPtr);
EndUpdate(gMyWindowPtr);
SetPort(savePort);
}
default: ;
}
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| Dispatch the menus.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void DoCommand( long menuChoice )
{
int theMenu;
int theItem;
if ( menuChoice != 0 )
{
theMenu = HiWord( menuChoice );
theItem = LoWord( menuChoice );
switch ( theMenu )
{
case 400:
HandleAppleChoice( theItem );
break;
case 401:
HandleFileChoice( theItem );
break;
default: ;
}
HiliteMenu( 0 );
}
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| Dispatch selections made in the Apple menu.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void HandleAppleChoice( int theItem )
{
Str255 accName;
int accNumber;
switch ( theItem ) {
case 1: AboutDialog();
break;
default:
GetItem( gMyMenus[0], theItem, accName );
accNumber = OpenDeskAcc( accName );
break;
}
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| Dispatch selections made in the File menu.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void HandleFileChoice( int theItem )
{
OSErr myErr = noErr;
switch ( theItem ) {
case 1: gDone = true;
break;
default: ;
}
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| Dispatch the button clicks in our window to routines which call the engine.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void DispatchOurWindowClicks()
{
short i = 0;
Boolean done = false;
Point tempP;
tempP = gTheEvent.where;
GlobalToLocal(&tempP);
while ((i < 6) && (!done)) {
if (PtInRect(tempP,&gRect[i])) {
done = true;
InvertRect(&gRect[i]);
}
else i++;
}
if (done) {
while (StillDown());
InvertRect(&gRect[i]);
switch(i) {
case 0: InitTheTextPertEngine();
break;
case 1: OpenAnImage();
break;
case 2: AnalyzeTheImage();
break;
case 3: ReadTheImage();
break;
case 4: DisposeTheImageAndTheLayout();
break;
case 5: FreeTheEngine();
break;
default: ErrorAlert("\pSomething happened that wasn't supposed to!!!");
break;
}
DrawDialog(gMyWindowPtr);
}
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| The following six routines are the real meat and patatoes of this example.
| They demonstrate the essential calls that are necessary to work with the
| TextPert OCR engine.
|
| InitTheTextPertEngine calls TPAlloc, which should be the first call that you make
| when working with the TextPert engine. Effectively, TPAlloc will launch the
| TextPert engine and initialize global variables that are necessary for the
| engine's operation. After this we must call TLoadLib to load the default
| library, and TPSet of the necessary parameters for engine's operation,
| (the most important are the CallBacks, but in our example we don't use it.
|
| Always remember to check the engineStatus by calling TPError after every call
| to the engine to ensure that a noErr result is returned.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void InitTheTextPertEngine()
{
DialogPtr myDialogPtr = 0L;
GrafPtr tempGrafPtr = 0L;
short Error=0;
if (!hTP) {
/*—————• Show some screen feedback for the user. */
SetCursor(&gWatchCursor);
myDialogPtr = GetNewDialog(404, 0L , ((WindowPtr) -1L));
if (!myDialogPtr) {
ErrorAlert("\pCouldn't load the wait dialog.");
}
ParamText("\pNow initializing the TextPert engine...", 0L , 0L , 0L);
GetPort(&tempGrafPtr);
BringToFront(myDialogPtr);
ShowWindow(myDialogPtr);
DrawDialog(myDialogPtr);
/*—————• Initialize the TextPert engine. */
hTP = TPAlloc(true);
if ((signed long)hTP>0)
{
TPLoadLib(hTP,nil);
Error=TPError(hTP);
}
if (((signed long)hTP<=0) || (Error!=0))
InformAlert("\pThe call to TPNew was not successful. The engine has not been initialized.");
else {
ShowDItem(gMyWindowPtr,2);
DrawDialog(gMyWindowPtr);
}
/*—————• Clean up the dialog mess and restore the original cursor and window. */
HideWindow(myDialogPtr);
SetPort(tempGrafPtr);
DisposeDialog(myDialogPtr);
SetCursor(&qd.arrow);
}
else {
InformAlert("\pSorry dude. You've already initialized the engine.");
}
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| OpenAnImage will display a three-button dialog for the user to determine whether
| the image will be obtained from disk or from scanner or cancel the operation.
| If the image is obtained from disk, the Page Analysis Module call IMTiff2hIM will
| be called to input the TIFF image and will return an engine-generated handle to
| the image (called an IMHandle). If you are interested in obtaining images from a
| scanner, the scanner routines in this example demonstrated the necessary steps
| for scanner input.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void OpenAnImage()
{
short choice = 0;
if (hTP) {
if (!hIM) {
choice = ShowImageChoiceDialog();
switch (choice) {
case 1: InputImageFromDisk();
break;
case 2: InputImageFromScanner();
break;
default: break;
}
if (hIM) {
ShowDItem(gMyWindowPtr,3);
}
}
else {
InformAlert("\pNo can do. Before you obtain another image you should dispose of the one you already have.");
}
}
else {
InformAlert("\pNo way man. You can't open an image before you initialize the engine.");
}
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| AnalyzeTheImage sets up the LOParams structure for the areas that are identified
| as text in the image, and obtains a second hIM for an image that is scaled to
| 75 dpi compared to the original image. With an hIM for a reduced image, this
| routine calls PAObtainObjects which automatically
| analyzes the image and creates a layout specification that identifies the
| text blocks in the image.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void AnalyzeTheImage()
{
IMHandle redhIM = 0L;
short resolution = 0,rowBytes = 0;
Rect bounds;
DialogPtr myDialogPtr = 0L;
GrafPtr tempGrafPtr = 0L;
/*—————• Before performing automatic page analysis, you must have an hTP and an hIM. */
if ((hTP) && (hIM)) {
/*—————• Set up some screen feedback for the user. */
SetCursor(&gWatchCursor);
myDialogPtr = GetNewDialog(404, 0L , ((WindowPtr) -1L));
if (!myDialogPtr)
ErrorAlert("\pCouldn't load the wait dialog.");
ParamText("\pNow identifying the elements in the image...\nThis process may take a few minutes.", 0L , 0L , 0L);
GetPort(&tempGrafPtr);
BringToFront(myDialogPtr);
ShowWindow(myDialogPtr);
DrawDialog(myDialogPtr);
/*—————• Get rid of any old hLO. */
if (hLO) {
LTFree(hLO);
hLO = 0L;
if (TPError(hTP) != noErr)
EngineError();
}
/*—————• Obtain an hIM reference to a reduced image at 75 dpi */
redhIM = IMNewScale(hIM,75,IM_AUTO,gStartUpVolume);
if (TPError(hTP) != noErr) {
EngineError();
}
else {
if (redhIM) {
/*—————• Have the TextPert engine analyze the page */
hLO = PAObtainObjects(redhIM,0L,nil,PA_TEXT+PA_HEADLINES);
if (TPError(hTP) != noErr) {
EngineError();
}
IMFree(redhIM);
if (TPError(hTP) != noErr) {
EngineError();
}
else {
if (hLO) {
/*•———————————————————————————————————————————————————•
| VERY, VERY, IMPORTANT.
| After obtaining an hLO for the reduced image at
| 75 dpi, you must get the resolution of your
| original image (NOT of the reduced image) and
| convert the resolution of the layout specification
| to the resolution of the original image.
•———————————————————————————————————————————————————•*/
IMGetInfo( hIM , &resolution , &bounds , &rowBytes );
if (TPError(hTP) != noErr) {
EngineError();
}
else {
if (resolution) {
LTSet(hLO,LT_RESOLUTION,(long)resolution);
if (TPError(hTP) != noErr) {
EngineError();
}
else
ShowDItem(gMyWindowPtr,4);
}
}
}
else
InformAlert("\pWow. For some reason the page analysis process didn't create a layout specification. Oh well.");
}
}
else
InformAlert("\pError: The reduced image was not created. Bummer man.");
}
/*—————• Clean up the dialog mess and restore the original cursor and window. */
HideWindow(myDialogPtr);
SetPort(tempGrafPtr);
DisposeDialog(myDialogPtr);
SetCursor(&qd.arrow);
}
else
InformAlert("\pWrong answer. Before the engine can analyze an image, the engine must first be initialized and there must be an image to analyze.");
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| ReadTheImage accesses the central call of the TextPert engine, RDRead. Before
| making this call, make sure you have obtained an hTP, hIM, hLO, and have
| created a large enough text buffer for the engine to dump the output text to.
| Before call RDRead, you must call TPSet to indicate the buffer for the
| output text and the length of this buffer.
| The ReadTheImage routine dumps the text in the buffer to a text file called
| TP Text Found.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void ReadTheImage()
{
OSErr myError = noErr;
Str255 fileName = "\pTP Text Found";
Str255 temp1,temp2,temp3;
DialogPtr myDialogPtr = 0L;
GrafPtr tempGrafPtr = 0L;
short itemHit = 0;
Rect btnRect = {105,131,125,189};
short fRef = 0;
long count = 0L;
long errorCount = 0L;
short i = 0;
float accuracy = 0;
/*—————• Make sure there is an hTP, an hIM, and an hLO. */
if ((hTP) && (hIM) && (hLO)) {
/*—————• Set up the cursor and a dialog for user feedback. */
SetCursor(&gWatchCursor);
myDialogPtr = GetNewDialog(404, 0L , ((WindowPtr) -1L));
if (!myDialogPtr)
ErrorAlert("\pCouldn't load the wait dialog.");
ParamText("\pNow reading the text in the image...\nThis process may take a few minutes.", 0L , 0L , 0L);
GetPort(&tempGrafPtr);
BringToFront(myDialogPtr);
ShowWindow(myDialogPtr);
DrawDialog(myDialogPtr);
/*—————• Create a text output buffer. Preferably as big as possible. */
TextOutBufferPtr = (TPTextOut *)NewPtr(30000);
myError = MemError();
if (!myError) {
(*TextOutBufferPtr).length = 0;
/*—————• Call TPRead to have the TextPert engine perform the OCR process. */
TPSet(hTP,TP_TEXTOUT_BUFFER,(long)TextOutBufferPtr);
TPSet(hTP,TP_TEXTOUT_LENGTH,(long)29996); /* better leave 4 bytes free (2 bytes length and 2 more) */
RDRead(hTP,hIM,hLO);
if (TPError(hTP) != noErr)
EngineError();
else {
/*—————• For this example, we will write the text to a text file. */
ParamText("\pNow saving the text as a text file 'TP Text Found' ...", 0L , 0L , 0L);
DrawDialog(myDialogPtr);
myError = FSDelete(fileName, gStartUpVolume);
myError = Create(fileName, gStartUpVolume, 'MPS ', 'TEXT');
if (myError == noErr) {
myError = FSOpen(fileName, gStartUpVolume, &fRef);
if (myError == noErr) {
count = (*TextOutBufferPtr).length;
myError = FSWrite(fRef, &count, (Ptr)&(*TextOutBufferPtr).text);
if (myError != noErr)
InformAlert("\pError occured while writing the text to the text file.");
myError = FSClose(fRef);
}
else
InformAlert("\pError occured while attempting to open the text output file.");
}
else
InformAlert("\pError occured while attempting to create the text output file.");
}
/*—————• Get the statistics */
count = (*TextOutBufferPtr).length;
errorCount = 0;
for (i=0;i<count;i++) {
if ((*TextOutBufferPtr).text[i] == '•')
errorCount++;
}
sprintf((char *)temp1,"Characters Read: %ld",count);
c2pstr(temp1);
sprintf((char *)temp2,"Unidentified Characters: %ld",errorCount);
c2pstr(temp2);
accuracy = (count - errorCount) * 100;
sprintf((char *)temp3,"Approx. Accuracy: %.3f%%",(accuracy / count));
c2pstr(temp3);
/*—————• Free the space occuppied by the text output buffer. */
DisposPtr((Ptr)TextOutBufferPtr);
}
else
InformAlert("\pError occured while attempting to create the text out buffer.");
/*—————• Clean up the dialog mess and restore the original cursor and window. */
HideWindow(myDialogPtr);
SetPort(tempGrafPtr);
DisposeDialog(myDialogPtr);
SetCursor(&qd.arrow);
/*—————• If there were characters read, show the results dialog */
if (count)
ParamText(temp1,temp2,temp3,0L);
myDialogPtr = GetNewDialog(410, 0L , ((WindowPtr) -1L));
if (!myDialogPtr)
ErrorAlert("\pCouldn't load the choice dialog.");
/*—————• Bring the dialog to the screen and frame the default button */
GetPort(&tempGrafPtr);
SetPort(myDialogPtr);
BringToFront(myDialogPtr);
ShowWindow(myDialogPtr);
PenNormal();
PenSize(3,3);
InsetRect(&btnRect,-4,-4);
FrameRoundRect(&btnRect,16,16);
HearSnd();
/*—————• Wait for the reply from the user */
ModalDialog( 0L , &itemHit );
/*—————• Hide the dialog and dispose of its mess */
HideWindow( myDialogPtr );
SetPort(tempGrafPtr);
DisposeDialog(myDialogPtr);
}
else
InformAlert("\pBefore performing the OCR process, you must first initialize the engine, and then obtain an image and a layout specification.");
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| DisposeTheImageAndTheLayout is responsible for disposing of the image and the
| layout specification. PLEASE NOTE: disposing of an image and disposing of a
| layout specification do not have to be done at the same time. They are only
| disposed simultaneously for this example program. You could, for instance,
| create one layout specification that is used for reading multiple images.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void DisposeTheImageAndTheLayout()
{
if ((hIM) || (hLO)) {
SetCursor(&gWatchCursor);
if (hIM) {
IMFree(hIM);
hIM = 0L;
if (TPError(hTP) != noErr)
EngineError();
}
if (hLO) {
LTFree(hLO);
hLO = 0L;
if (TPError(hTP) != noErr)
EngineError();
}
HideDItem(gMyWindowPtr,3);
HideDItem(gMyWindowPtr,4);
SetCursor(&qd.arrow);
}
else {
InformAlert("\pSorry. Can't dispose of something that you don't already have.");
}
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| FreeTheEngine is responsible for release the TextPert engine. NEVER try
| to check the "engineStatus" by calling TPError after a call to TPDispose.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void FreeTheEngine()
{
if (hTP) {
SetCursor(&gWatchCursor);
if ((hIM) || (hLO))
DisposeTheImageAndTheLayout();
TPDispose(hTP);
hTP = 0L;
HideDItem(gMyWindowPtr,2);
SetCursor(&qd.arrow);
gShowStart = true;
}
else {
InformAlert("\pWhoops. Before you try to release the engine you might want to try initializing it first.");
}
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| The ShowImageChoiceDialog routine displays a dialog that let's the user choose
| whether to load an image from disk or from scanner or to cancel the operation.
•———————————————————————————————————————————————————————————————————————————————————•*/
static short ShowImageChoiceDialog()
{
DialogPtr myDialogPtr = 0L;
GrafPtr tempGrafPtr = 0L;
short itemHit;
Rect btnRect = {53,205,73,263};
Boolean myReturn = false;
myDialogPtr = GetNewDialog(403, 0L , ((WindowPtr) -1L));
if (!myDialogPtr)
ErrorAlert("\pCouldn't load the choice dialog.");
/*—————• Bring the dialog to the screen and frame the default button */
GetPort(&tempGrafPtr);
SetPort(myDialogPtr);
BringToFront(myDialogPtr);
ShowWindow(myDialogPtr);
PenNormal();
PenSize(3,3);
InsetRect(&btnRect,-4,-4);
FrameRoundRect(&btnRect,16,16);
/*—————• Wait for the reply from the user */
ModalDialog( 0L , &itemHit );
/*—————• Hide the dialog and dispose of its mess */
HideWindow( myDialogPtr );
SetPort(tempGrafPtr);
DisposeDialog(myDialogPtr);
DrawDialog(gMyWindowPtr);
return((short)(LoWord(itemHit)));
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| The InputImageFromDisk displays the Standard File dialog box, then opens
| the user-selected file. The file reference number is then passed to the engine
| in the call to IMTiff2hIM.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void InputImageFromDisk()
{
OSErr myError = noErr;
short refNum;
SFTypeList myTypeList;
StandardFileReply theReply;
DialogPtr myDialogPtr;
GrafPtr tempGrafPtr;
myTypeList[0] = 'TIFF';
/*—————• Use the standard get file dialog box to obtain user's request. */
StandardGetFile(0L,1,myTypeList,&theReply);
DrawDialog(gMyWindowPtr);
/*—————• See if the user made a choice or canceled. */
if (theReply.sfGood) {
/*—————• Show some screen feedback for the user. */
SetCursor(&gWatchCursor);
myDialogPtr = GetNewDialog(404, 0L , ((WindowPtr) -1L));
if (!myDialogPtr) {
ErrorAlert("\pCouldn't load the wait dialog.");
}
ParamText("\pNow loading the TIFF image...", 0L , 0L , 0L);
GetPort(&tempGrafPtr);
BringToFront(myDialogPtr);
ShowWindow(myDialogPtr);
DrawDialog(myDialogPtr);
/*—————• Open the image to obtain the file reference number. */
myError = FSpOpenDF(&theReply.sfFile,fsCurPerm, &refNum);
if (myError == noErr) {
/*—————• Just in case...Get rid of any old hIM. */
if (hIM) {
IMFree(hIM);
hIM = 0L;
if (TPError(hTP) != noErr)
EngineError();
}
/*—————• Call the engine to have it input the TIFF image. */
hIM = IMTiff2hIM( hTP , refNum , IM_AUTO , gStartUpVolume );
if (TPError(hTP) != noErr)
EngineError();
myError = FSClose(refNum);
}
else
InformAlert("\pAn error occured while trying to open the file containing the image.");
/*—————• Clean up the dialog mess and restore the original cursor and window. */
HideWindow(myDialogPtr);
SetPort(tempGrafPtr);
DisposeDialog(myDialogPtr);
SetCursor(&qd.arrow);
}
}
/*•———————————————————————————————————————————————————————————————————————————————————•
|
| ••• WARNING •••
|
| THIS NEXT ROUTINE IS FOR EXPERIENCED PROGRAMMERS ONLY. NOT FOR THE WEAK AT HEART!
|
| The code used within this routine contains advanced Macintosh and TextPert
| programming techniques. This code has been provided to demonstrate some
| advanced capabilities of the TextPert engine when used in conjunction with
| a scanner.
|
|
| The InputImageFromScanner routine displays a dialog which allows users to
| change the brightness and the contrast before scanning. After the scan is
| complete, a reduced version of the image is shown in the dialog. If the user
| clicks on the image, the image is magnified to display the portion of the
| image at the point of the click. This routine calls the ScanImage routine which
| is located in the Example 1_Scan.c file.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void InputImageFromScanner()
{
short lineCount = 0,lineCountMag = 0,rRes;
IMHandle reducedhIM = 0L,
magnifiedhIM = 0L;
Handle tempHdl = 0L;
DialogPtr myDialogPtr = 0L;
GrafPtr tempGrafPtr = 0L;
short itemHit,vLines,hLines;
Boolean done = false,AlreadyReduced = true;
Str255 tempStr1;
Str255 tempStr2;
Str255 tempStr3;
BitMap srcBits,srcBitsMag;
Rect dstRect = {15,30,315,226};
Rect imageOutLineRect = {13,28,317,228};
Rect scanRect,fromRect,toRect;
Point where;
BitMap tempBitMap;
myDialogPtr = GetNewDialog(405, 0L , ((WindowPtr) -1L));
if (!myDialogPtr)
ErrorAlert("\pCouldn't load the scan dialog.");
/*—————• Bring the dialog to the screen */
GetPort(&tempGrafPtr);
SetPort(myDialogPtr);
BringToFront(myDialogPtr);
ShowWindow(myDialogPtr);
PenNormal();
FrameRect(&imageOutLineRect);
/*—————• Wait for and process the dialog events from the user until finished */
while (!done) {
/*—————• Make the strings for the scanner settings */
sprintf((char *)tempStr1,"Brightness: %hd%%",(gBrightness * 10));
sprintf((char *)tempStr2,"Contrast: %hd%%",(gContrast * 10));
sprintf((char *)tempStr3,"Resolution: %hd dpi",gResolution);
c2pstr(tempStr1);
c2pstr(tempStr2);
c2pstr(tempStr3);
ParamText(tempStr1,tempStr2,tempStr3,0L);
/*—————• Update the dialog */
DrawDialog(myDialogPtr);
/*—————• Wait for the user's response */
ModalDialog( 0L , &itemHit );
switch( itemHit ) {
case 2:
/*—————• See if the mouse click occurred in the image area of the dialog */
GetMouse(&where);
if (!(PtInRect(where,&dstRect)))
break;
/*—————• Process this request only if there exists all sizes of the image */
if ((!hIM) || (!reducedhIM))
break;
SetCursor(&gWatchCursor);
EraseRect(&dstRect);
/*—————• if true, show the magnified image, else show reduced image */
if (AlreadyReduced) {
if (TPError(hTP) != noErr)
EngineError();
/*—————• Map the mouse click to the magnified image */
MapPt(&where,&dstRect,&srcBitsMag.bounds);
/*—————• Center the point to the display rectangle */
vLines = dstRect.bottom - dstRect.top;
hLines = dstRect.right - dstRect.left;
where.v = where.v - (vLines / 2);
where.h = where.h - (hLines / 2);
if (where.v > (srcBitsMag.bounds.bottom - vLines))
where.v = srcBitsMag.bounds.bottom - vLines;
if (where.v < srcBitsMag.bounds.top)
where.v = srcBitsMag.bounds.top;
if (where.h > (srcBitsMag.bounds.right - hLines))
where.h = srcBitsMag.bounds.right - hLines;
if (where.h < srcBitsMag.bounds.left)
where.h = srcBitsMag.bounds.left;
if (vLines > lineCountMag)
vLines = lineCountMag;
SetRect(&fromRect,where.h,0,where.h + hLines,vLines);
tempBitMap = srcBitsMag;
tempBitMap.bounds.bottom = tempBitMap.bounds.top + lineCountMag;
IMLockZone(magnifiedhIM,where.v,vLines,&tempBitMap.baseAddr);
if (TPError(hTP) != noErr)
EngineError();
CopyBits(&tempBitMap,&(*((GrafPort *)myDialogPtr)).portBits,
&fromRect,&toRect,srcCopy,0L);
IMUnlockZone(magnifiedhIM);
}
else {
/*—————• Show the reduced image */
CopyBits(&srcBits,&(*((GrafPort *)myDialogPtr)).portBits,
&srcBits.bounds,&dstRect,srcCopy,0L);
}
AlreadyReduced = !AlreadyReduced;
SetCursor(&qd.arrow);
break;
case 4:
SetCursor(&gWatchCursor);
EraseRect(&dstRect);
/*—————• Just in case...Get rid of the old hIMs. */
if (tempHdl = IMGetHdl(hIM))
DisposHandle(tempHdl);
PurgehIM(&hIM);
PurgehIM(&reducedhIM);
PurgehIM(&magnifiedhIM);
/*—————• Set up the 8.5" x 12" rectangular area for the scan. */
SetRect(&scanRect,0,0,((gResolution * 8) + (gResolution/2)),(gResolution * 12));
/*—————• Scan the image */
hIM = ScanImage(&scanRect,gResolution,gBrightness,gContrast,gStartUpVolume);
if (hIM) {
/*•————————————————————————————————————————————————————————————————•
| For this example program, we create a scaled version
| of the original scanned image: at 12 dpi.
•————————————————————————————————————————————————————————————————•*/
reducedhIM = IMNewScale( hIM , 12 , IM_AUTO , gStartUpVolume );
if (TPError(hTP) != noErr)
EngineError();
/*—————• If there's a valid reduced image, copy it to the dialog */
if (reducedhIM) {
lineCount = IMGetMaxStrip(reducedhIM);
if (TPError(hTP) != noErr)
EngineError();
IMGetInfo(reducedhIM,&rRes,&srcBits.bounds,&srcBits.rowBytes);
if (TPError(hTP) != noErr)
EngineError();
if (lineCount > (srcBits.bounds.bottom - srcBits.bounds.top))
lineCount = srcBits.bounds.bottom - srcBits.bounds.top;
IMLockZone(reducedhIM,0,lineCount,&srcBits.baseAddr);
if (TPError(hTP) != noErr)
EngineError();
CopyBits(&srcBits,&(*((GrafPort *)myDialogPtr)).portBits,
&srcBits.bounds,&dstRect,srcCopy,0L);
}
/*—————• Create an actual size version of the image */
magnifiedhIM = IMNewScale( hIM , 72 , IM_AUTO , gStartUpVolume );
if (TPError(hTP) != noErr)
EngineError();
/*—————• If there's a valid image, get its info */
if (magnifiedhIM) {
lineCountMag = IMGetMaxStrip(magnifiedhIM);
if (TPError(hTP) != noErr)
EngineError();
IMGetInfo(magnifiedhIM,&rRes,&srcBitsMag.bounds,&srcBitsMag.rowBytes);
if (TPError(hTP) != noErr)
EngineError();
if (lineCountMag > (srcBitsMag.bounds.bottom - srcBitsMag.bounds.top))
lineCountMag = srcBitsMag.bounds.bottom - srcBitsMag.bounds.top;
toRect = dstRect;
if (lineCountMag < (toRect.bottom - toRect.top))
toRect.bottom = toRect.top + lineCountMag;
}
}
AlreadyReduced = true;
SetCursor(&qd.arrow);
break;
case 5:
done = true;
break;
case 8:
if (gBrightness < 10)
gBrightness++;
break;
case 9:
if (gBrightness > 0)
gBrightness--;
break;
case 10:
if (gContrast < 10)
gContrast++;
break;
case 11:
if (gContrast > 0)
gContrast--;
break;
default:
break;
}
}
/*—————• Get rid of the space allocated for the reduced images */
PurgehIM(&reducedhIM);
PurgehIM(&magnifiedhIM);
/*—————• Hide the dialog and dispose of its mess */
HideWindow( myDialogPtr );
SetPort(tempGrafPtr);
DisposeDialog(myDialogPtr);
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| The PurgehIM is a minor utility routine that calls the TextPert routine
| which deallocates the space allocated for an image.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void PurgehIM(IMHandle *thehIM)
{
if (*thehIM) {
IMUnlockZone(*thehIM);
if (TPError(hTP) != noErr)
EngineError();
IMFree(*thehIM);
*thehIM = 0L;
if (TPError(hTP) != noErr)
EngineError();
}
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| The ShowMainWindow routine displays the selection menu.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void ShowMainWindow()
{
int i;
/*•——————————————————————————————•
| Preset the check boxes.
•——————————————————————————————•*/
for (i=2;i<5;i++)
HideDItem(gMyWindowPtr,i);
BringToFront(gMyWindowPtr);
ShowWindow(gMyWindowPtr);
SetPort(gMyWindowPtr);
DrawDialog(gMyWindowPtr);
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| The ShowStartDialog routine was merely added for marketing sex appeal.
•———————————————————————————————————————————————————————————————————————————————————•*/
static Boolean ShowStartDialog()
{
DialogPtr myDialogPtr = 0L;
GrafPtr tempGrafPtr = 0L;
short itemHit;
Rect btnRect = {314,99,335,195};
Boolean myReturn = false;
myDialogPtr = GetNewDialog(400, 0L , ((WindowPtr) -1L));
if (!myDialogPtr)
ErrorAlert("\pCouldn't load the startup dialog.");
/*—————• Bring the dialog to the screen and frame the default button */
GetPort(&tempGrafPtr);
SetPort(myDialogPtr);
BringToFront(myDialogPtr);
ShowWindow(myDialogPtr);
PenNormal();
PenSize(3,3);
InsetRect(&btnRect,-4,-4);
FrameRoundRect(&btnRect,16,16);
/*—————• Wait for the reply from the user */
ModalDialog( 0L , &itemHit );
switch( itemHit ) {
case 1:
myReturn = false;
break;
case 2:
myReturn = true;
break;
default:
break;
}
/*—————• Hide the dialog and dispose of its mess */
HideWindow( myDialogPtr );
SetPort(tempGrafPtr);
DisposeDialog(myDialogPtr);
return(myReturn);
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| The AboutDialog routine displays the "About..." dialog. Not needed for OCR!!!
•———————————————————————————————————————————————————————————————————————————————————•*/
static void AboutDialog()
{
DialogPtr myDialogPtr = 0L;
GrafPtr tempGrafPtr = 0L;
short itemHit;
Rect btnRect = {266,298,286,356};
myDialogPtr = GetNewDialog(401, 0L , ((WindowPtr) -1L));
if (!myDialogPtr)
ErrorAlert("\pCouldn't load the About dialog.");
/*—————• Bring the dialog to the screen and frame the default button */
GetPort(&tempGrafPtr);
SetPort(myDialogPtr);
BringToFront(myDialogPtr);
ShowWindow(myDialogPtr);
PenNormal();
PenSize(3,3);
InsetRect(&btnRect,-4,-4);
FrameRoundRect(&btnRect,16,16);
/*—————• Wait for the reply from the user */
ModalDialog( 0L , &itemHit );
/*—————• Hide the dialog and dispose of its mess */
HideWindow( myDialogPtr );
SetPort(tempGrafPtr);
DisposeDialog(myDialogPtr);
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| The InformAlert routine is used as a central dispatch to display various
| messages that occur during the execution of the code.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void InformAlert( Str255 myString )
{
SetCursor(&qd.arrow);
ParamText( myString, 0L , 0L , 0L );
NoteAlert(-16411 , 0L );
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| The ErrorAlert routine is used as a central dispatch to display the results of
| error conditions that occur during the execution of the code. These are for
| unrecoverable errors when the program should not be permitted to continue.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void ErrorAlert( Str255 myString )
{
SetCursor(&qd.arrow);
ParamText( myString, 0L , 0L , 0L );
StopAlert(-16411 , 0L );
ExitToShell();
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| The EngineError routine is used as a central call to display the results of
| engine error conditions that occur during the execution of the code.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void EngineError()
{
char temp[256];
SetCursor(&qd.arrow);
sprintf((char *)temp,"The TextPert Engine has identified an error condition. Error: %hd",
TPError(hTP));
c2pstr(temp);
ParamText( *(Str255 *)temp, 0L , 0L , 0L );
CautionAlert(-16411 , 0L );
}
/*•———————————————————————————————————————————————————————————————————————————————————•
| Sound routine for debug and other attention getting activities.
•———————————————————————————————————————————————————————————————————————————————————•*/
static void HearSnd()
{
Handle soundHandle = 0L;
if (( soundHandle = GetResource( 'snd ', 1 )) != 0L)
SndPlay( 0L, soundHandle, false);
}
/*==================================== THE END =====================================*/